use chrono::{DateTime, Duration, Local};
use log::info;
use serde::{Deserialize, Serialize};
use serde_json;
use std::fs;
use std::path::Path;

// 自定义日期时间序列化模块
mod datetime_format {
    use chrono::{DateTime, Local, TimeZone};
    use serde::{self, Deserialize, Deserializer, Serializer};

    const FORMAT: &str = "%Y-%m-%d %H:%M:%S";

    pub fn serialize<S>(date: &DateTime<Local>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let s = format!("{}", date.format(FORMAT));
        serializer.serialize_str(&s)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Local>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        
        // 尝试解析简洁格式 "YYYY-MM-DD HH:MM:SS"
        if let Ok(naive) = chrono::NaiveDateTime::parse_from_str(&s, FORMAT) {
            return Ok(Local.from_local_datetime(&naive).single()
                .ok_or_else(|| serde::de::Error::custom("Invalid local time"))?);
        }
        
        // 兼容旧的 ISO 8601 格式
        DateTime::parse_from_rfc3339(&s)
            .map(|dt| dt.with_timezone(&Local))
            .map_err(serde::de::Error::custom)
    }
}

mod datetime_vec_format {
    use chrono::{DateTime, Local, TimeZone};
    use serde::{self, Deserialize, Deserializer, Serializer};

    const FORMAT: &str = "%Y-%m-%d %H:%M:%S";

    pub fn serialize<S>(dates: &Vec<DateTime<Local>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        use serde::ser::SerializeSeq;
        let mut seq = serializer.serialize_seq(Some(dates.len()))?;
        for date in dates {
            let s = format!("{}", date.format(FORMAT));
            seq.serialize_element(&s)?;
        }
        seq.end()
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<DateTime<Local>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let strings: Vec<String> = Vec::deserialize(deserializer)?;
        let mut result = Vec::new();
        
        for s in strings {
            // 尝试解析简洁格式
            if let Ok(naive) = chrono::NaiveDateTime::parse_from_str(&s, FORMAT) {
                if let Some(dt) = Local.from_local_datetime(&naive).single() {
                    result.push(dt);
                    continue;
                }
            }
            
            // 兼容旧的 ISO 8601 格式
            if let Ok(dt) = DateTime::parse_from_rfc3339(&s) {
                result.push(dt.with_timezone(&Local));
            }
        }
        
        Ok(result)
    }
}

mod datetime_option_format {
    use chrono::{DateTime, Local, TimeZone};
    use serde::{self, Deserialize, Deserializer, Serializer};

    const FORMAT: &str = "%Y-%m-%d %H:%M:%S";

    pub fn serialize<S>(date: &Option<DateTime<Local>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match date {
            Some(dt) => {
                let s = format!("{}", dt.format(FORMAT));
                serializer.serialize_some(&s)
            }
            None => serializer.serialize_none(),
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Local>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let opt: Option<String> = Option::deserialize(deserializer)?;
        
        match opt {
            Some(s) => {
                // 尝试解析简洁格式
                if let Ok(naive) = chrono::NaiveDateTime::parse_from_str(&s, FORMAT) {
                    if let Some(dt) = Local.from_local_datetime(&naive).single() {
                        return Ok(Some(dt));
                    }
                }
                
                // 兼容旧的 ISO 8601 格式
                if let Ok(dt) = DateTime::parse_from_rfc3339(&s) {
                    return Ok(Some(dt.with_timezone(&Local)));
                }
                
                Ok(None)
            }
            None => Ok(None),
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DayCounter {
    #[serde(with = "datetime_format")]
    pub start_date: DateTime<Local>,
    #[serde(with = "datetime_vec_format")]
    pub executed_dates: Vec<DateTime<Local>>,
    #[serde(with = "datetime_format")]
    pub last_check_date: DateTime<Local>,
    pub total_days: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub remaining_days: Option<u32>,
    #[serde(with = "datetime_option_format", skip_serializing_if = "Option::is_none", default)]
    pub next_execution_time: Option<DateTime<Local>>,
}

impl DayCounter {
    pub fn new(total_days: u32) -> Self {
        let now = Local::now();
        let remaining = if total_days > 0 { Some(total_days) } else { None };
        Self {
            start_date: now,
            executed_dates: Vec::new(),
            last_check_date: now,
            total_days,
            remaining_days: remaining,
            next_execution_time: None,
        }
    }

    pub fn from_file(file_path: &str, total_days: u32) -> Result<Self, Box<dyn std::error::Error>> {
        if Path::new(file_path).exists() {
            let content = fs::read_to_string(file_path)?;
            let mut counter: DayCounter = serde_json::from_str(&content)?;
            counter.total_days = total_days;
            Ok(counter)
        } else {
            Ok(Self::new(total_days))
        }
    }

    pub fn save_to_file(&self, file_path: &str) -> Result<(), Box<dyn std::error::Error>> {
        // 创建目录(如果不存在)
        if let Some(parent) = Path::new(file_path).parent() {
            fs::create_dir_all(parent)?;
        }
        
        let content = serde_json::to_string_pretty(self)?;
        fs::write(file_path, content)?;
        Ok(())
    }

    pub fn can_execute_today(&mut self) -> bool {
        if self.total_days > 0 && (self.executed_dates.len() as u32) >= self.total_days {
            info!(
                "Task reached the configured limit of {} days; execution paused",
                self.total_days
            );
            return false;
        }

        true
    }

    pub fn record_execution(&mut self) {
        let now = Local::now();
        let today = now.date_naive();

        // 检查今天是否已经记录过
        let already_recorded = self.executed_dates.iter()
            .any(|dt| dt.date_naive() == today);

        if !already_recorded {
            self.executed_dates.push(now);
            self.cleanup_old_records();
        }

        self.last_check_date = now;
        
        // 更新剩余天数
        self.remaining_days = self.get_remaining_days();

        info!(
            "Recorded execution at {}; progress {}/{}",
            now.format("%Y-%m-%d %H:%M:%S"),
            self.executed_dates.len(),
            self.total_days
        );
    }

    fn cleanup_old_records(&mut self) {
        if self.total_days == 0 {
            let cutoff = Local::now() - Duration::days(30);
            self.executed_dates.retain(|dt| *dt >= cutoff);
        }
    }

    pub fn get_progress(&self) -> (u32, u32) {
        // 计算不同日期的数量
        let mut unique_dates = std::collections::HashSet::new();
        for dt in &self.executed_dates {
            unique_dates.insert(dt.date_naive());
        }
        let executed_days = unique_dates.len() as u32;
        (executed_days, self.total_days)
    }

    pub fn get_remaining_days(&self) -> Option<u32> {
        if self.total_days == 0 {
            return None;
        }

        // 计算不同日期的数量
        let mut unique_dates = std::collections::HashSet::new();
        for dt in &self.executed_dates {
            unique_dates.insert(dt.date_naive());
        }
        let executed_days = unique_dates.len() as u32;
        Some(self.total_days.saturating_sub(executed_days))
    }
}
